﻿/*
 * Copyright (c) 2015 Datacratic.  All rights reserved.
 * SPDX-FileCopyrightText: 2015 Mathieu Stefani
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#pragma once

#include <cstddef>
#include <functional>

namespace Pistache
{
    /*
     * 该类为不同的类型生成唯一的标识符，利用模板和静态变量的特性实现这一功能
     *
     * 工作原理：
     * 当你为某个类型 T 调用 TypeId::of<T>() 时，会为该类型生成一个静态的 char 变量，
     * 并返回这个变量的地址封装在 TypeId 对象中。由于每个类型都会有一个独立的静态变量，
     * 因此每个类型都会有一个唯一的 TypeId 对象。通过比较这些 TypeId 对象，
     * 你可以判断两个 TypeId 是否代表相同的类型
     *
     * 用途：
     * 这个 TypeId 类可以用于类型识别、类型比较等场景，特别是在需要基于类型做出决策时非常有用。
     * 比如，在实现类型擦除（type erasure）、类型安全的容器或者需要基于类型进行分支选择时，
     * TypeId 可以提供一个简单而有效解决方案
     */
    class TypeId
    {
    public:
        template <typename T>
        static TypeId of()
        {
            static char const id_ {};

            return TypeId(&id_);
        }

        explicit operator size_t() const { return reinterpret_cast<size_t>(id_); }

    private:
        typedef void const* Id;

        explicit TypeId(Id id)
            : id_(id)
        { }

        Id id_;
    };

    /*
     * TypeId比较器
     *
     * 在使用自定义哈希函数时，你还需要提供一个相等的比较函数（通常是通过特化 std::equal_to 或者提供一个自定义的比较器），
     * 以便在哈希表中正确地比较键
     */
#define APPLY_OP(lhs, rhs, op) \
    static_cast<size_t>(lhs) op static_cast<size_t>(rhs);

    inline bool operator==(const TypeId& lhs, const TypeId& rhs)
    {
        return APPLY_OP(lhs, rhs, ==);
    }

    inline bool operator!=(const TypeId& lhs, const TypeId& rhs)
    {
        return APPLY_OP(lhs, rhs, !=);
    }

    inline bool operator<(const TypeId& lhs, const TypeId& rhs)
    {
        return APPLY_OP(lhs, rhs, <);
    }

#undef APPLY_OP

} // namespace Pistache

namespace std
{
    /*
     * 这段代码定义了一个模板特化（template specialization）的结构体 hash<TypeId>，
     * 用于为 TypeId 类型提供一个自定义的哈希函数。
     *
     * 这个哈希函数是 std::hash 的一个特化版本，它允许 TypeId 对象被用作
     * 哈希表（如 std::unordered_map 或 std::unordered_set）的键
     *
     * 使用场景：
     * 这个自定义的哈希函数允许你将 TypeId 对象用作哈希表的键。
     * 例如，你可以创建一个 std::unordered_map<TypeId, ValueType>，
     * 其中 ValueType 是你想要与每个类型关联的值类型。这样，
     * 你就可以根据类型来快速查找或存储与之关联的值了
     */
    template <>
    struct hash<Pistache::TypeId>
    {
        size_t operator()(const Pistache::TypeId& id)
        {
            return static_cast<size_t>(id);
        }
    };
} // namespace std
